﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HttpRequester.RequestMakers.Base;
using Helpers;

namespace HttpRequester
{
    public abstract class RequestChainItemBase : RequestInfo, IRequestStatus
    {
        #region IRequestStatus Members

        public bool? IsSuccessfulyInvoked { get; set; }
        public bool? ProcessFlag { get; set; }
        public bool IsInvoked { get; set; }
        public bool IsInProgress { get; set; }

        #endregion

        public virtual string Name { get { return this.GetType().Name; } }
        public RequestInvokationInfo InvokationInfo { get; set; }
        public bool IsRequestInProgress { get; set; }
        public string ResponseContent { get; set; }


        public override void Clear()
        {
            base.Clear();

            IsSuccessfulyInvoked = null;
            ProcessFlag = null;
            IsInvoked = false;
            IsInProgress = false;
            IsRequestInProgress = false;

            InvokationInfo = new RequestInvokationInfo(this);
        }


        public abstract bool IsContextValid();
        public abstract void PrepareRequest();
        public abstract bool IsRequestValid();
        public abstract void DoRequest();
        public abstract bool IsResponseValid();
        public abstract void UpdateContext();
    }



    public abstract class RequestChainItemBase<TRequester, TChain, TContext> : RequestChainItemBase
        where TRequester : RequestManagerPlaneHtml
        where TChain : RequestChain<TContext>
        where TContext : RequestChainContext, new()
    {
        public TChain Chain { get; set; }

        public TRequester Requester { get; set; }
        


        public override void Clear()
        {
            base.Clear();

            Requester = Activator.CreateInstance<TRequester>();
        }



        #region IsContextValidInternal

        protected virtual bool IsContextValidInternal()
        {
            return true;
        }

        public override bool IsContextValid()
        {
            IsInProgress = true;
            
            bool result = true;

            if (Chain == null)
            {
                InvokationInfo.AddException("Chain is null!");
                return false;
            }

            result &= IsContextValidInternal();

            return result;
        }

        #endregion IsContextValidInternal

        
        #region PrepareRequest

        protected virtual void BeforePrepareRequestInternal() { }
        protected virtual void PrepareRequestInternal() { }
        protected virtual void AfterPrepareRequestInternal() { }

        public override void PrepareRequest()
        {
            BeforePrepareRequestInternal();

            if (Chain != null)
            {
                Requester.Context.Proxy = Chain.Context.Proxy;
                Requester.Context.LoadInputCookies(Chain.Context.InputCookies.Values.ToList());
                Requester.Context.LoadHeaders(Chain.Context.CommonCustomHeaders, Chain.Context.CommonWellknownHeaders);
            }

            PrepareRequestInternal();

            Requester.Context.LoadInputCookies(Context.InputCookies.Values.ToList());
            Requester.Context.LoadHeaders(Context.CommonCustomHeaders, Context.CommonWellknownHeaders);
            Requester.LoadGetData(GetMembers);
            Requester.LoadPostData(PostMembers);
            Requester.Method = Method;
            Requester.ContentType = ContentType;
            Requester.Url = Url;

            AfterPrepareRequestInternal();
        }
        
        #endregion IsContextValidInternal


        #region IsRequestValid

        protected virtual bool IsRequestValidInternal()
        {
            return true;
        }
        
        public override bool IsRequestValid()
        {
            bool result = true;
            result &= UrlHelper.IsUrlCorrect(Requester.Url);
            if (!result)
            {
                InvokationInfo.AddError("Incorrect URL : " + Requester.Url);
                return result;
            }

            result &= IsRequestValidInternal();

            return result; 
        }

        #endregion IsRequestValid


        #region DoRequest

        public virtual void BeforeDoRequest() { }
        public virtual void AfterDoRequest() { }

        public override void DoRequest()
        {
            IsRequestInProgress = true;

            BeforeDoRequest();

            try
            {
                Requester.DoRequest();
                ResponseContent = Requester.PageContent;
            }
            catch (Exception ex)
            {
                InvokationInfo.AddException(ex.Message);
                throw;
            }

            AfterDoRequest();

            IsRequestInProgress = false;
        }

        #endregion DoRequest


        #region IsResponseValid

        public virtual bool IsResponseValidInternal()
        {
            return true;
        }

        public override bool IsResponseValid()
        {
            bool result = true;

            result &= !StringHelper.IsnullOrBlank(Requester.PageContent);
            if (!result)
            {
                InvokationInfo.AddError("Empty PageContent");
                return result;
            }

            result &= IsResponseValidInternal();

            return result; 
        }

        #endregion IsResponseValid


        #region UpdateContext

        public virtual void BeforeUpdateContext() { }
        public virtual void AfterUpdateContext() { }

        public override void UpdateContext()
        {
            BeforeUpdateContext();

            if (Chain != null)
            {
                Chain.LastContent = Requester.PageContent;
                Chain.LoadInputCookies(Requester.OutputCookies);
            }

            IsInProgress = false;
            IsInvoked = true;

            AfterUpdateContext();
        }

        #endregion UpdateContext


        public void DoIndividualRequest()
        {
            ProcessFlag = true;
            try
            {
                ProcessFlag = IsContextValid();
                if (ProcessFlag.HasValue && (!ProcessFlag.Value))
                    throw new ChainInvokationIsFailedException("Context is Not Valid");

                try
                {
                    PrepareRequest();
                }
                catch (Exception ex)
                {
                    throw new ChainInvokationIsFailedException("Request prepearing was failed", ex);
                }

                ProcessFlag = IsRequestValid();
                if (ProcessFlag.HasValue && (!ProcessFlag.Value))
                    throw new ChainInvokationIsFailedException("Request is Not Valid");

                try
                {
                    DoRequest();
                }
                catch (Exception ex)
                {
                    throw new ChainInvokationIsFailedException("Request was done with problems", ex);
                }

                ProcessFlag = IsResponseValid();
                if (ProcessFlag.HasValue && (!ProcessFlag.Value))
                    throw new ChainInvokationIsFailedException("Response is Not Valid");

                try
                {
                    UpdateContext();
                }
                catch (Exception ex)
                {
                    throw new ChainInvokationIsFailedException("Context Update was not done correct", ex);
                }

                IsSuccessfulyInvoked = true;
            }
            catch (ChainInvokationIsFailedException ex)
            {
                ProcessFlag = false;
                IsSuccessfulyInvoked = false;
            }
        }
    }
}
